package com.spring.framework.config.autowired;

import com.spring.framework.config.autowired.model.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * 前面我们讲了一些bean注册的注解，有@Repository、@Service、@Controller、@Bean，对于类或者方法这些注解表示将bean交给IoC容器管理，
 * 然后我们就可以从IoC容器中获取对应bean名称的实例对象了。我们同样可以使用注解实现属性注入。
 * <p>
 * ps:@Autowired注解实际上就是Spring提供的一个依赖自动注入的注解，在此前基于XML的配置文章中，我们就曾经了解过自动注入，XML的自动注入
 * 都是通过构造器或者setter方法，并且还有各种各样的限制，@Autowired注解则使用更加灵活方便，功能也更加强大！同样，@Autowired要求其所
 * 在的类被注册到IoC容器中。JSR-330的@Inject注解可以一定程度上代替Spring的@Autowired注解。
 * <p>
 * ps:@Autowired可以用在构造器、属性、方法上，甚至，某些时候不使用该注解就能实现自动注入。@Autowired注解是使用 AutowiredAnnotationBeanPostProcessor
 * 处理器来解析的，后面的文章会分析BeanPostProcessor的原理，现在先学习如何使用。
 * <p>
 * ps:@Autowired的自动注入规则如下：
 * <ul>
 *     <li>首先在容器中查询要注入参数、属性的对应类型的bean（类型可以向下兼容匹配）；</li>
 *     <li>如果只查询到一个，就将该bean实例注入进去到对应类型的参数、属性中，没查询到则抛出异常；</li>
 *     <li>如果查询的结果不止一个，那么继续根据属性、参数名称作为bean name来查找；</li>
 *     <li>如果查询到使用该参数作为name的bean，就将该bean实例注入进去到对应类型的参数、属性中。那么如果没查询到，那么会抛出异常。</li>
 * </ul>
 * <p>
 *
 * @author xuweizhi
 * @since 2020/12/15 10:34
 */
@Configuration
@ComponentScan(basePackages = {"com.spring.framework.config.autowired"})
public class AutowiredConfig {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AutowiredConfig.class);
		System.out.println(applicationContext.getBean("autowiredConstructorDemo", AutowiredConstructorDemo.class));
		System.out.println("==================================");
		System.out.println(applicationContext.getBean("autowiredConstructorOptionalDemo", AutowiredConstructorOptionalDemo.class));
		// @Nullable 功实现“有就注入，没有就不注入”的功能，并且没有抛出异常：
		System.out.println(applicationContext.getBean("autowiredConstructorNullableDemo", AutowiredConstructorNullableDemo.class));
		System.out.println(applicationContext.getBean( AutowiredPrimaryDemo.class));

		System.out.println("==================================");
		System.out.println(applicationContext.getBean("autowiredQualifierDemo", AutowiredQualifierDemo.class));
		//通过@Bean返回的getAutowiredQualifierDemo对象和交给IoC容器管理的autowiredQualifierDemo对象的属性是同一个对象
		//这就是在前面说的@Bean对于已经交给IoC容器自动管理的bean的自动注入问题，我们在@Bean中设置的属性被覆盖了。
		System.out.println(applicationContext.getBean("getAutowiredQualifierDemo", AutowiredQualifierDemo.class));
	}
}

